package com.example.springbootdemo.aspect;

import com.example.springbootdemo.SysLog;
import com.example.springbootdemo.annotation.Auditable;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;

@Component
@Aspect
@Slf4j // 使用 Lombok 提供的 @Slf4j 注解，自动生成 Logger 实例
public class AuditAspect {
    // 定义一个静态日志对象，用于记录审计日志
    private static final Logger logger = LoggerFactory.getLogger(AuditAspect.class);

    // 使用 @Around 注解定义一个环绕通知，匹配带有 @Auditable 注解的方法
    @Around("@annotation(auditable)")
    public Object audit(ProceedingJoinPoint joinPoint, Auditable auditable) throws Throwable {
        // 获取被拦截方法的名称
        String methodName = joinPoint.getSignature().getName();

        // 获取 @Auditable 注解的 value 值，通常用于描述审计信息
        String message = auditable.value();

        // 获取被拦截方法的参数数组
        Object[] args = joinPoint.getArgs();

        // 将参数数组转换为字符串，便于记录日志
        String argsString = args != null ? Arrays.stream(args)
                .map(Objects::toString)
                .collect(Collectors.joining(",")) : "";

        // 创建一个 SysLog 对象，用于记录审计日志
        SysLog sysLog = new SysLog(methodName, message, argsString, null, null, null);

        try {
            // 执行被拦截的方法，并获取返回值
            Object result = joinPoint.proceed();

            // 如果方法执行成功，记录返回值和状态
            sysLog.setResult(result != null ? result.toString() : "null");
            sysLog.setStatus("成功");

            // 返回方法的原始结果
            return result;
        } catch (Throwable e) {
            // 如果方法抛出异常，记录异常信息和状态
            sysLog.setStatus("失败");
            sysLog.setException(e.getMessage());

            // 重新抛出异常，以便上层可以处理
            throw e;
        } finally {
            // 无论方法执行成功还是失败，都记录审计日志
            logger.info("日志审计记录成功：{}", sysLog);
        }
    }
}